package com.qingyun.web.security.filter;

import com.alibaba.fastjson.JSON;
import com.qingyun.common.constant.Constants;
import com.qingyun.common.core.domain.model.LoginBody;
import com.qingyun.common.utils.MessageUtils;
import com.qingyun.framework.web.service.AsyncService;
import com.qingyun.security.config.TenantContextHolder;
import com.qingyun.security.enums.LoginRole;
import com.qingyun.security.exception.AuthoException;
import com.qingyun.web.security.handle.LoginAuthFailedHandler;
import com.qingyun.web.security.handle.LoginAuthSuccessHandler;
import com.qingyun.web.security.token.AdminAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * @author dangyonghang
 */
@Component
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    @Value("${login.url}")
    private static String loginUrl="/admin/login";

    private AuthenticationManager authenticationManager;

    @Autowired
    private AsyncService asyncService;

    public LoginAuthenticationFilter()
    {
        super(new AntPathRequestMatcher(loginUrl, "POST"));
    }

    @Autowired
    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
        this.authenticationManager=authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
        String stringFromStream = getStringFromStream(httpServletRequest);
        LoginBody loginBody = JSON.parseObject(stringFromStream, LoginBody.class);
        AdminAuthenticationToken adminAuthenticationToken = new AdminAuthenticationToken(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid());
        Authentication authenticate=null;
      try{
        TenantContextHolder.setTenantType(LoginRole.SYS);
        authenticate = authenticationManager.authenticate(adminAuthenticationToken);
       }
        catch (Exception e) {
            if (e instanceof BadCredentialsException) {
				asyncService.recordLogininfor(loginBody.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"), httpServletRequest);
                throw new AuthoException(e.getMessage());
            } else {
				asyncService.recordLogininfor(loginBody.getUsername(), Constants.LOGIN_FAIL, e.getMessage(),httpServletRequest);
                throw new AuthoException(e.getMessage());
            }
        }finally {
          TenantContextHolder.clearTenantType();
        }
		asyncService.recordLogininfor(loginBody.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), httpServletRequest);
        return authenticate;
    }



    @Resource
    public void setAuthenticationSuccessHandler(LoginAuthSuccessHandler LoginAuthSuccessHandler) {
        super.setAuthenticationSuccessHandler(LoginAuthSuccessHandler);
    }

    @Resource
    public void setAuthenticationFailureHandler(LoginAuthFailedHandler LoginAuthFailedHandler) {
        super.setAuthenticationFailureHandler(LoginAuthFailedHandler);
    }

    private String getStringFromStream(HttpServletRequest req) {
        ServletInputStream is;
        try {
            is = req.getInputStream();
            int nRead = 1;
            int nTotalRead = 0;
            byte[] bytes = new byte[10240];
            while (nRead > 0) {
                nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
                if (nRead > 0) {
                    nTotalRead = nTotalRead + nRead;
                }
            }
            return new String(bytes, 0, nTotalRead, StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
